home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume17 / delete / part04 < prev    next >
Encoding:
Internet Message Format  |  1991-02-25  |  28.1 KB

  1. From: jik@pit-manager.MIT.EDU (Jonathan I. Kamens)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i026:  delete - MIT Athena delete/undelete programs, Part04/04
  4. Message-ID: <1991Feb25.180800.4445@sparky.IMD.Sterling.COM>
  5. Date: 25 Feb 91 18:08:00 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 490d39b9 6fab43d0 b6f4ab40 93ea5bf3
  8.  
  9. Submitted-by: Jonathan I. Kamens <jik@pit-manager.MIT.EDU>
  10. Posting-number: Volume 17, Issue 26
  11. Archive-name: delete/part04
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then unpack
  15. # it by saving it into a file and typing "sh file".  To overwrite existing
  16. # files, type "sh file -c".  You can also feed this as standard input via
  17. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  18. # will see the following message at the end:
  19. #        "End of archive 4 (of 4)."
  20. # Contents:  pattern.c
  21. # Wrapped by jik@pit-manager on Fri Feb 22 08:14:28 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'pattern.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'pattern.c'\"
  25. else
  26. echo shar: Extracting \"'pattern.c'\" \(25764 characters\)
  27. sed "s/^X//" >'pattern.c' <<'END_OF_FILE'
  28. X/*
  29. X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/pattern.c,v $
  30. X * $Author: jik $
  31. X *
  32. X * This program is part of a package including delete, undelete,
  33. X * lsdel, expunge and purge.  The software suite is meant as a
  34. X * replacement for rm which allows for file recovery.
  35. X * 
  36. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  37. X * For copying and distribution information, see the file "mit-copyright.h."
  38. X */
  39. X
  40. X#if (!defined(lint) && !defined(SABER))
  41. X     static char rcsid_pattern_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/pattern.c,v 1.21 91/02/20 17:27:03 jik Exp $";
  42. X#endif
  43. X
  44. X#include <stdio.h>
  45. X#include <sys/types.h>
  46. X#include <sys/dir.h>
  47. X#include <sys/param.h>
  48. X#ifdef SYSV
  49. X#include <string.h>
  50. X#define index strchr
  51. X#define rindex strrchr
  52. X#else
  53. X#include <strings.h>
  54. X#endif /* SYSV */
  55. X#include <errno.h>
  56. X#include <com_err.h>
  57. X#include "pattern.h"
  58. X#include "util.h"
  59. X#include "directories.h"
  60. X#include "undelete.h"
  61. X#include "shell_regexp.h"
  62. X#include "mit-copyright.h"
  63. X#include "delete_errs.h"
  64. X#include "errors.h"
  65. X#include "stack.h"
  66. X
  67. Xextern char *realloc();
  68. Xextern int errno;
  69. Xextern char *whoami;
  70. X
  71. Xvoid free_list();
  72. X
  73. X
  74. X/*
  75. X * add_arrays() takes pointers to two arrays of char **'s and their
  76. X * lengths, merges the two into the first by realloc'ing the first and
  77. X * then free's the second's memory usage.
  78. X */  
  79. Xint add_arrays(array1, num1, array2, num2)
  80. Xchar ***array1, ***array2;
  81. Xint *num1, *num2;
  82. X{
  83. X     int counter;
  84. X     
  85. X     *array1 = (char **) realloc((char *) *array1, (unsigned)
  86. X                 (sizeof(char *) * (*num1 + *num2)));
  87. X     if (! *array1) {
  88. X      set_error(errno);
  89. X      error("realloc");
  90. X      return error_code;
  91. X     }
  92. X     for (counter = *num1; counter < *num1 + *num2; counter++)
  93. X      *(*array1 + counter) = *(*array2 + counter - *num1);
  94. X     free ((char *) *array2);
  95. X     *num1 += *num2;
  96. X     return 0;
  97. X}
  98. X
  99. X
  100. X
  101. X
  102. X
  103. X
  104. X/*
  105. X * Add a string to a list of strings.
  106. X */
  107. Xint add_str(strs, num, str)
  108. Xchar ***strs;
  109. Xint num;
  110. Xchar *str;
  111. X{
  112. X     char **ary;
  113. X
  114. X     ary = *strs = (char **) realloc((char *) *strs, (unsigned)
  115. X                     (sizeof(char *) * (num + 1)));
  116. X     if (! *strs) {
  117. X      set_error(errno);
  118. X      error("realloc");
  119. X      return error_code;
  120. X     }
  121. X     ary[num] = Malloc((unsigned) (strlen(str) + 1));
  122. X     if (! ary[num]) {
  123. X      set_error(errno);
  124. X      error("Malloc");
  125. X      return error_code;
  126. X     }
  127. X     (void) strcpy(ary[num], str);
  128. X     return 0;
  129. X}
  130. X
  131. X
  132. X
  133. X
  134. X
  135. X/*
  136. X * Find_matches will behave unpredictably if you try to use it to find
  137. X * very strange combinations of file types, for example only searching
  138. X * for undeleted files in the top-level directory, while searching
  139. X * recursively for deleted files.  Basically, there are some conflicts
  140. X * between options that I don't list here because I don't think I'll
  141. X * ever need to use those combinations.
  142. X */
  143. X/*
  144. X * Function: find_matches(char *name, int *num_found, char ***found,
  145. X *                 int options)
  146. X *
  147. X * Requires: name points to a NULL-terminated string, representing a
  148. X *   filename pattern with regular filename characters, path
  149. X *   separators and shell wildcard characters []*?; num_found points
  150. X *   to a valid int memory storage location; found points to a valid
  151. X *   char ** memory storage location.
  152. X *
  153. X * Effects: Returns a list of all the files in the file hierarchy that
  154. X *   match the options specified in options and that match name.
  155. X *   Options are:
  156. X *
  157. X *   FIND_UNDELETED search for and return undeleted files
  158. X * 
  159. X *   FIND_DELETED search for and return deleted files
  160. X *
  161. X *   FIND_CONTENTS means that if matches are directories (or links to
  162. X *     directories), the contents of the directory should be matched
  163. X *     in addition to the directory itself
  164. X * 
  165. X *   RECURS_FIND_DELETED to search all undeleted subdirectories
  166. X *     recursively of matched directories looking for deleted files
  167. X *
  168. X *   RECURS_FIND_UNDELETED to search all undeleted subdirectories
  169. X *     recursively of matched directories looking for undeleted files
  170. X * 
  171. X *   RECURS_DELETED to recursively return all contents of deleted
  172. X *     directories in addition to the directories themselves
  173. X *   
  174. X *   FOLLW_LINKS to pursue symlinks to directories and continue down
  175. X *     the referenced directories when searching recursively (if the
  176. X *     initial string is an undeleted symlink it is always traversed;
  177. X *     deleted symlinks are never traversed)
  178. X *   
  179. X *   FOLLW_MOUNTPOINTS to traverse mount points when searching
  180. X *     recursively (if the initial string is a mountpoint it is always
  181. X *     traversed)
  182. X *
  183. X *   FIND_DOTFILES forces the system to recognize dot files instead of
  184. X *     discarding them when looking for files
  185. X *
  186. X *   If the first character of name is '/', the search is conducted
  187. X *   absolutely from the root of the hierarchy; else, it is conducted
  188. X *   relative to the current working directory.  The number of
  189. X *   matching files is returned in *num_found, and a list of file
  190. X *   names is returned in *found.  If there are no errors, the return
  191. X *   value is 0; else the return value represents the error code of
  192. X *   the error which occurred.  No matter how many file names are
  193. X *   returned, the memory location addressed in *found is a valid
  194. X *   pointer according to Malloc() and can be released using free()
  195. X *   safely.  However, if an error value is returned, the caller
  196. X *   should not attempt to use the values stored in *num_found or
  197. X *   *found.
  198. X *
  199. X * Modifies: *num_found, *found.
  200. X */
  201. Xint find_matches(name, num_found, found, options)
  202. Xchar *name;
  203. Xint *num_found;
  204. Xchar ***found;
  205. Xint options;
  206. X{
  207. X     char     **matched_files, **return_files, **recurs_files;
  208. X     int     num_matched_files = 0, num_return_files = 0,
  209. X                num_recurs_files = 0;
  210. X     int    retval;
  211. X     int    i;
  212. X#ifdef DEBUG
  213. X     int    j;
  214. X#endif
  215. X     int    match_options = 0;
  216. X
  217. X#ifdef DEBUG
  218. X     fprintf(stderr, "Entering find_matches, name = %s, options = %d.\n",
  219. X         name, options);
  220. X#endif
  221. X     
  222. X     match_options = options & (FIND_DELETED | FIND_UNDELETED);
  223. X     if (options & (RECURS_FIND_DELETED | RECURS_FIND_UNDELETED |
  224. X            FIND_CONTENTS))
  225. X      match_options |= FIND_UNDELETED;
  226. X     
  227. X     if (! match_options) {
  228. X      set_error(PAT_NO_FILES_REQUESTED);
  229. X      error("find_matches");
  230. X      return error_code;
  231. X     }
  232. X     
  233. X     retval = do_match(name, &num_matched_files, &matched_files,
  234. X               match_options & FIND_UNDELETED,
  235. X               match_options & FIND_DELETED);
  236. X     if (retval) {
  237. X      error(name);
  238. X      return retval;
  239. X     }
  240. X     if (num_matched_files == 0) {
  241. X      *num_found = num_matched_files;
  242. X      *found = matched_files;
  243. X#ifdef DEBUG
  244. X      fprintf(stderr, "No matches found, returning.\n");
  245. X#endif
  246. X      return 0;
  247. X     }
  248. X
  249. X#ifdef DEBUG
  250. X     fprintf(stderr, "The following matches were found:\n");
  251. X     for (i = 0; i < num_matched_files; i++)
  252. X      fprintf(stderr, "  %s\n", matched_files[i]);
  253. X#endif
  254. X     
  255. X     if (options & RECURS) {
  256. X      return_files = (char **) Malloc(0);
  257. X      if (! return_files) {
  258. X           set_error(errno);
  259. X           error("Malloc");
  260. X           return error_code;
  261. X      }
  262. X      num_return_files = 0;
  263. X
  264. X      for (i = 0; i < num_matched_files; i++) {
  265. X
  266. X           retval = do_recurs(matched_files[i], &num_recurs_files,
  267. X                  &recurs_files, options);
  268. X           if (retval) {
  269. X            error(matched_files[i]);
  270. X            return retval;
  271. X           }
  272. X
  273. X           if (num_recurs_files) {
  274. X            retval = add_arrays(&return_files, &num_return_files,
  275. X                    &recurs_files, &num_recurs_files);
  276. X            if (retval) {
  277. X             error("add_arrays");
  278. X             return retval;
  279. X            }
  280. X#ifdef DEBUG
  281. X            fprintf(stderr,
  282. X                "Just added the following to return_files:\n");
  283. X            for (j = num_return_files - num_recurs_files;
  284. X             j < num_return_files; j++)
  285. X             fprintf(stderr, "  %s\n", return_files[j]);
  286. X#endif
  287. X           }
  288. X           
  289. X           if (is_deleted(lastpart(matched_files[i]))) {
  290. X            if (options & FIND_DELETED) {
  291. X             retval = add_str(&return_files, num_return_files,
  292. X                      matched_files[i]);
  293. X             if (retval) {
  294. X                  error("add_str");
  295. X                  return retval;
  296. X             }
  297. X             num_return_files++;
  298. X#ifdef DEBUG
  299. X             fprintf(stderr, "Just added %s to return_files.\n",
  300. X                 return_files[num_return_files-1]);
  301. X#endif
  302. X            }
  303. X           }
  304. X           else if (options & FIND_UNDELETED) {
  305. X            retval = add_str(&return_files, num_return_files,
  306. X                     matched_files[i]);
  307. X            if (retval) {
  308. X             error("add_str");
  309. X             return retval;
  310. X            }
  311. X            num_return_files++;
  312. X#ifdef DEBUG
  313. X            fprintf(stderr, "Just added %s to return_files.\n",
  314. X                return_files[num_return_files-1]);
  315. X#endif
  316. X           }
  317. X      }
  318. X      free_list(matched_files, num_matched_files);
  319. X      *num_found = num_return_files;
  320. X      *found = return_files;
  321. X     }
  322. X     else {
  323. X      *num_found = num_matched_files;
  324. X      *found = matched_files;
  325. X     }
  326. X
  327. X     return 0;
  328. X}
  329. X
  330. X
  331. X
  332. X
  333. X      
  334. X      
  335. X            
  336. X           
  337. X#define string_push(str)\
  338. X      strsize = strlen(str);\
  339. X      retval = push(str, strsize);\
  340. X      if (! retval)\
  341. X           retval |= push(&strsize, sizeof(int));\
  342. X      if (retval) {\
  343. X           error("push");\
  344. X           (void) popall();\
  345. X           return retval;\
  346. X      }
  347. X#define string_pop(str)\
  348. X      retval = pop(&strsize, sizeof(int));\
  349. X      if (! retval)\
  350. X           retval = pop(str, strsize);\
  351. X      if (! retval)\
  352. X           str[strsize] = '\0'
  353. X      
  354. X      
  355. X
  356. X
  357. X
  358. X
  359. X/*
  360. X * Function: do_match(char *name, int *num_found, char ***found,
  361. X *               Boolean match_undeleted, Boolean match_deleted)
  362. X *
  363. X * Requires: name points to a NULL-terminated string, representing a
  364. X *   filename pattern with regular filename characters, path
  365. X *   separators and shell wildcard characters []*?; num_found points
  366. X *   to a valid int memory storage location; found points to a valid
  367. X *   char ** memory storage location.
  368. X *
  369. X * Effects: Returns a list of all the files in the file hierarchy that
  370. X *   match name.  If match_undeleted is true, will return undeleted
  371. X *   files that match; if match_deleted is true, will return
  372. X *   deleted_files that match.  If the first character of name is '/',
  373. X *   the search is conducted absolutely from the root of the
  374. X *   hierarchy; else, it is conducted relative to the current working
  375. X *   directory.  The number of matching files is returned in
  376. X *   *num_found, and a list of file names is returned in *found.  If
  377. X *   there are no errors, the return value is 0; else the return value
  378. X *   represents the error code of the error which occurred.  No matter
  379. X *   how many file names are returned, the memory location addressed
  380. X *   in *found is a valid pointer according to Malloc() and can be
  381. X *   released using free() safely.  However, if an error value is
  382. X *   returned, the caller should not attempt to use the values stored
  383. X *   in *num_found or *found.
  384. X *
  385. X * Modifies: *num_found, *found.
  386. X *
  387. X * Algorithm:
  388. X *
  389. X * start:
  390. X *   base = "" or "/",
  391. X *   name = name or name + 1
  392. X *   initialze found and num_found
  393. X *   dirp = Opendir(base)
  394. X *   first = firstpart(name, rest) (assigns rest as side-effect)
  395. X *   if (! *first) {
  396. X *     add string to list if appropriate
  397. X *     return
  398. X * 
  399. X * loop:
  400. X *   dp = readdir(dirp)
  401. X *   if (! dp) goto updir
  402. X *   compare dp->d_name to first -- match?
  403. X *     yes - goto downdir
  404. X *     no - are we looking for deleted and is dp->d_name deleted?
  405. X *       yes - compare undeleted dp->d_name to first -- match?
  406. X *         yes - goto downdir
  407. X *         no - goto loop
  408. X *       no - goto loop
  409. X *
  410. X * downdir:
  411. X *   save dirp, rest, first and base on stack
  412. X *   first = firstpart(rest, rest)
  413. X *   base = dp->d_name appended to base
  414. X *   is first an empty string?
  415. X *      yes - put back dirp, rest, first, base
  416. X *            goto loop
  417. X *   try to open dir base - opens?
  418. X *      yes - goto loop
  419. X *      no - is the error ENOTDIR?
  420. X *           yes - don't worry about it
  421. X *            no - report the error
  422. X *          restore dirp, rest, first, base from stack
  423. X *           goto loop
  424. X *
  425. X * updir:
  426. X *   close dirp
  427. X *   restore base, rest, first from stack
  428. X *   STACK_EMPTY?
  429. X *     yes - return from procedure with results
  430. X *   restore dirp from stack
  431. X *   goto loop
  432. X */
  433. Xint do_match(name, num_found, found, match_undeleted, match_deleted)
  434. Xchar *name;
  435. Xint *num_found;
  436. Xchar ***found;
  437. XBoolean match_undeleted, match_deleted;
  438. X{
  439. X     char base[MAXPATHLEN];
  440. X     struct direct *dp;
  441. X     DIR *dirp;
  442. X     char first[MAXNAMLEN], rest[MAXPATHLEN];
  443. X     int retval;
  444. X     int strsize;
  445. X     struct stat statbuf;
  446. X#ifdef PATTERN_DEBUG
  447. X     int j;
  448. X#endif
  449. X     
  450. X#ifdef DEBUG
  451. X     printf("do_match: looking for %s\n", name);
  452. X#endif
  453. X
  454. X     /* start: */
  455. X     
  456. X     if (*name == '/') {
  457. X      *base = '/';
  458. X      *(base + 1) = '\0';
  459. X      name++;
  460. X     }
  461. X     else 
  462. X      *base = '\0';
  463. X
  464. X     *found = (char **) Malloc(0);
  465. X     if (! *found) {
  466. X      set_error(errno);
  467. X      error("Malloc");
  468. X#ifdef PATTERN_DEBUG
  469. X      fprintf(stderr, "do_match: return 1.\n");
  470. X#endif
  471. X      return error_code;
  472. X     }
  473. X     *num_found = 0;
  474. X     
  475. X     dirp = Opendir(base);
  476. X     if (! dirp) {
  477. X      set_error(errno);
  478. X      error(base);
  479. X#ifdef PATTERN_DEBUG
  480. X      fprintf(stderr, "do_match: return 2.\n");
  481. X#endif
  482. X      return error_code;
  483. X     }
  484. X     (void) strcpy(first, firstpart(name, rest));
  485. X     if ((! *first) && (match_undeleted)) {
  486. X      retval = add_str(found, *num_found, base);
  487. X      if (retval) {
  488. X           error("add_str");
  489. X           (void) popall();
  490. X#ifdef PATTERN_DEBUG
  491. X           fprintf(stderr, "do_match: return 3.\n");
  492. X#endif
  493. X           return retval;
  494. X      }
  495. X      (*num_found)++;
  496. X#ifdef PATTERN_DEBUG
  497. X      fprintf(stderr, "do_match: return 4.\n");
  498. X#endif
  499. X      return 0;
  500. X     }
  501. X     
  502. X     while (1) {
  503. X      dp = readdir(dirp);
  504. X      if (! dp) goto updir;
  505. X
  506. X      retval = reg_cmp(first, dp->d_name);
  507. X#ifdef PATTERN_DEBUG
  508. X    fprintf(stderr, "do_match: comparing %s to %s returns %d.\n",
  509. X        first, dp->d_name, retval);
  510. X#endif
  511. X      if (retval < 0) {
  512. X           error("reg_cmp");
  513. X           goto updir;
  514. X      }
  515. X
  516. X      if (retval == REGEXP_MATCH) goto downdir;
  517. X
  518. X      if (is_deleted(dp->d_name) && match_deleted) {
  519. X           retval = reg_cmp(first, &dp->d_name[2]);
  520. X#ifdef PATTERN_DEBUG
  521. X           fprintf(stderr,
  522. X               "do_match: deleted compare of %s to %s returns %d.\n",
  523. X               first, &dp->d_name[2], retval);
  524. X#endif
  525. X           if (retval < 0) {
  526. X            error("reg_cmp");
  527. X            goto updir;
  528. X           }
  529. X
  530. X           if (retval == REGEXP_MATCH)
  531. X            goto downdir;
  532. X           else
  533. X            continue;
  534. X      }
  535. X      else
  536. X           continue;
  537. X
  538. X     downdir:
  539. X#ifdef PATTERN_DEBUG
  540. X      fprintf(stderr, "do_match: downdir\n");
  541. X#endif
  542. X      retval = push(&dirp, sizeof(DIR *));
  543. X      if (retval) {
  544. X           error("push");
  545. X           (void) popall();
  546. X#ifdef PATTERN_DEBUG
  547. X           fprintf(stderr, "do_match: return 5.\n");
  548. X#endif
  549. X           return retval;
  550. X      }
  551. X#ifdef PATTERN_DEBUG
  552. X      fprintf(stderr, "do_match: pushing %s, %s, %s\n", first, rest, base);
  553. X#endif
  554. X      string_push(first);
  555. X      string_push(rest);
  556. X      string_push(base);
  557. X      (void) strcpy(base, append(base, dp->d_name));
  558. X      (void) strcpy(first, firstpart(rest, rest));
  559. X      if (! *first) {
  560. X           if (is_deleted(lastpart(base))) {
  561. X            if (match_deleted) {
  562. X             retval = add_str(found, *num_found, base);
  563. X             if (retval) {
  564. X                  error("add_str");
  565. X                  (void) popall();
  566. X#ifdef PATTERN_DEBUG
  567. X                  fprintf(stderr, "do_match: return 6.\n");
  568. X#endif
  569. X                  return retval;
  570. X             }
  571. X             (*num_found)++;
  572. X            }
  573. X           }
  574. X           else if (match_undeleted) {
  575. X            retval = add_str(found, *num_found, base);
  576. X            if (retval) {
  577. X             error("add_str");
  578. X             (void) popall();
  579. X#ifdef PATTERN_DEBUG
  580. X             fprintf(stderr, "do_match: return 7.\n");
  581. X#endif
  582. X             return retval;
  583. X            }
  584. X            (*num_found)++;
  585. X           }
  586. X           string_pop(base);
  587. X           string_pop(rest);
  588. X           string_pop(first);
  589. X#ifdef PATTERN_DEBUG
  590. X           fprintf(stderr, "do_match: popped %s, %s, %s\n", first,
  591. X               rest, base);
  592. X#endif
  593. X           (void) pop(&dirp, sizeof(DIR *));
  594. X           continue;
  595. X      }
  596. X
  597. X      if (! stat(base, &statbuf)) {
  598. X           if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  599. X            dirp = Opendir(base);
  600. X      }
  601. X      else {
  602. X           dirp = NULL;
  603. X      }
  604. X      if (! dirp) {
  605. X           set_error(errno);
  606. X           error(base);
  607. X           string_pop(base);
  608. X           string_pop(rest);
  609. X           string_pop(first);
  610. X#ifdef PATTERN_DEBUG
  611. X           fprintf(stderr, "do_match: popped %s, %s, %s\n", first,
  612. X               rest, base);
  613. X#endif
  614. X           (void) pop(&dirp, sizeof(DIR *));
  615. X           continue;
  616. X      }
  617. X      else 
  618. X           continue;
  619. X
  620. X     updir:
  621. X#ifdef PATTERN_DEBUG
  622. X      fprintf(stderr, "do_match: updir\n");
  623. X#endif
  624. X      closedir(dirp);
  625. X      string_pop(base);
  626. X#ifdef PATTERN_DEBUG
  627. X      fprintf(stderr, "do_match: popped %s\n", base);
  628. X#endif
  629. X      if (retval) {
  630. X           if (retval != STACK_EMPTY) {
  631. X            error("pop");
  632. X            (void) popall();
  633. X#ifdef PATTERN_DEBUG
  634. X            fprintf(stderr, "do_match: return 8.\n");
  635. X#endif
  636. X            return retval;
  637. X           }
  638. X#ifdef PATTERN_DEBUG
  639. X           fprintf(stderr, "Returning %d word%s from do_match:\n",
  640. X               *num_found,
  641. X               *num_found == 1 ? "" : "s");
  642. X           for (j = 0; j < *num_found; j++)
  643. X            fprintf(stderr, "\t%s\n", (*found)[j]);
  644. X           fprintf(stderr, "do_match: return 9.\n");
  645. X#endif
  646. X           return 0;
  647. X      }
  648. X      string_pop(rest);
  649. X      string_pop(first);
  650. X#ifdef PATTERN_DEBUG
  651. X      fprintf(stderr, "do_match: popped %s, %s\n", rest, first);
  652. X#endif
  653. X      retval = pop(&dirp, sizeof(DIR *));
  654. X      if (retval) {
  655. X           error("pop");
  656. X           (void) popall();
  657. X#ifdef PATTERN_DEBUG
  658. X           fprintf(stderr, "do_match: return 10.\n");
  659. X#endif
  660. X           return retval;
  661. X      }
  662. X      continue;
  663. X     }
  664. X}
  665. X
  666. X
  667. X
  668. X
  669. X
  670. X
  671. X/*
  672. X * Function: do_recurs(char *name, int *num_found, char ***found,
  673. X *                int options)
  674. X *
  675. X * Requires: name points to a NULL-terminated string, representing a
  676. X *   filename; points to a valid int memory storage location; found
  677. X *   points to a valid char ** memory storage location.
  678. X *
  679. X * Effects: Returns a list of all the files in the file hierarchy that
  680. X *   are underneath the specified file, governed by the options set in
  681. X *   options.  Options are as described in the find_matches() description.
  682. X *   RECURS_FIND_DELETED and RECURS_DELETED imply FIND_DELETED.
  683. X *   RECURS_FIND_UNDELETED implies FIND_UNDELETED.
  684. X *
  685. X * Modifies: *num_found, *found.
  686. X *
  687. X * Algorithm:
  688. X *
  689. X * start:
  690. X *   initialze found and num_found
  691. X *   strcopy(base, name)
  692. X *   check if we just opened a deleted symlink and return if we did
  693. X *   dirp = Opendir(base)
  694. X *   check RECURS options and set FIND options as appropriate
  695. X * 
  696. X * loop:
  697. X *   dp = readdir(dirp)
  698. X *   if (! dp) goto updir
  699. X *   is dp deleted?
  700. X *     yes - is FIND_DELETED set?
  701. X *             yes - add to list
  702. X *                   is RECURS_DELETED set?
  703. X *                   yes - goto downdir
  704. X *                     no - goto loop
  705. X *            no - goto loop
  706. X *     no - is FIND_UNDELETED set?
  707. X *            yes - is the file a dotfile?
  708. X *               yes - is FIND_DOTFILES set?
  709. X *                   yes - add to list
  710. X *                 goto loop
  711. X *               no - add to list
  712. X *                  are RECURS_FIND_DELETED and FIND_DELETED set?
  713. X *               yes - goto downdir
  714. X *                  is RECURS_FIND_UNDELETED set?
  715. X *               yes - goto downdir
  716. X *               no - goto loop
  717. X *           no - goto loop
  718. X *             
  719. X * downdir:
  720. X *   save dirp, base on stack
  721. X *   base = dp->d_name appended to base
  722. X *   try to open base -- opens?
  723. X *     yes - is FOLLW_LINKS set?
  724. X *             yes - is it deleted?
  725. X *              yes - is it a link?
  726. X *                yes - close the directory
  727. X *                  restore base and dirp
  728. X *                  goto loop
  729. X *             no - is it a link?
  730. X *                     yes - close the directory
  731. X *                  restore base and dirp
  732. X *                  goto loop
  733. X *           is FOLLW_MOUNTPOINTS set?
  734. X *             no - is it a mountpoint?
  735. X *                  yes - close the directory
  736. X *                           restore base and dirp
  737. X *                           goto loop
  738. X *     no - is the error ENOTDIR?
  739. X *           yes - don't worry about it
  740. X *           no - report the error
  741. X *         restore base and dirp
  742. X *          goto loop
  743. X * 
  744. X * updir:
  745. X *   close dirp
  746. X *   restore base from stack
  747. X *   STACK_EMPTY?
  748. X *     yes - return from procedure with results
  749. X *   restore dirp from stack
  750. X *   goto loop
  751. X */
  752. Xint do_recurs(name, num_found, found, options)
  753. Xchar *name;
  754. Xint *num_found;
  755. Xchar ***found;
  756. Xint options;
  757. X{
  758. X     char base[MAXPATHLEN];
  759. X     struct direct *dp;
  760. X     DIR *dirp;
  761. X     int retval;
  762. X     int strsize;
  763. X     struct stat statbuf;
  764. X     int use_stat;
  765. X
  766. X#ifdef DEBUG
  767. X     fprintf(stderr, "do_recurs: opening %s\n", name);
  768. X#endif
  769. X
  770. X     /* start: */
  771. X     
  772. X     *found = (char **) Malloc(0);
  773. X     if (! *found) {
  774. X      set_error(errno);
  775. X      error("Malloc");
  776. X      return error_code;
  777. X     }
  778. X     *num_found = 0;
  779. X     strcpy(base, name);
  780. X
  781. X     if (lstat(base, &statbuf)) {
  782. X      set_error(errno);
  783. X      error(base);
  784. X      return error_code;
  785. X     }
  786. X     
  787. X     if (is_link(base, &statbuf)) {
  788. X      /* Never follow deleted symlinks */
  789. X      if (is_deleted(lastpart(base))) {
  790. X           return 0;
  791. X      }
  792. X      if (stat(base, &statbuf)) {
  793. X           if (errno == ENOENT) {
  794. X            extern int readlink();
  795. X            char pathbuf[MAXPATHLEN];
  796. X            int cc;
  797. X            
  798. X            /* What the link is pointing to does not exist; */
  799. X            /* this is a warning, not an error.            */
  800. X            set_warning(errno);
  801. X            cc = readlink(base, pathbuf, MAXPATHLEN);
  802. X            if (cc > 0) {
  803. X             char error_buf[2*MAXPATHLEN+20];
  804. X
  805. X             pathbuf[(cc == MAXPATHLEN) ? (cc - 1) : cc] = '\0';
  806. X             sprintf(error_buf, "%s (pointed to by %s)", pathbuf,
  807. X                 base);
  808. X             error(error_buf);
  809. X            }
  810. X            else {
  811. X             error(base);
  812. X            }
  813. X
  814. X            return 0;
  815. X           }
  816. X           else {
  817. X            set_error(errno);
  818. X            error(base);
  819. X            return error_code;
  820. X           }
  821. X      }
  822. X     }
  823. X
  824. X     if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
  825. X      return 0;
  826. X     
  827. X     dirp = Opendir(base);
  828. X     if (! dirp) {
  829. X#ifdef DEBUG
  830. X      fprintf(stderr, "Couldn't open %s.\n", base);
  831. X#endif
  832. X      set_error(errno);
  833. X      error(base);
  834. X      return error_code;
  835. X     }
  836. X
  837. X     if (options & (RECURS_FIND_DELETED | RECURS_DELETED))
  838. X      options |= FIND_DELETED;
  839. X     if (options & RECURS_FIND_UNDELETED)
  840. X      options |= FIND_UNDELETED;
  841. X     
  842. X     while (1) {
  843. X      dp = readdir(dirp);
  844. X      if (! dp) goto updir;
  845. X
  846. X      if (is_deleted(dp->d_name)) {
  847. X           if (options & FIND_DELETED) {
  848. X            retval = add_str(found, *num_found,
  849. X                     append(base, dp->d_name));
  850. X            if (retval) {
  851. X             error("add_str");
  852. X             (void) popall();
  853. X             return retval;
  854. X            }
  855. X            (*num_found)++;
  856. X            if (options & RECURS_DELETED)
  857. X             goto downdir;
  858. X            else
  859. X             continue;
  860. X           }
  861. X           else
  862. X            continue;
  863. X      }
  864. X
  865. X      if (options & FIND_UNDELETED) {
  866. X           if (is_dotfile(dp->d_name)) {
  867. X            if (options & FIND_DOTFILES) {
  868. X             retval = add_str(found, *num_found,
  869. X                      append(base, dp->d_name));
  870. X             if (retval) {
  871. X                  error("add_str");
  872. X                  (void) popall();
  873. X                  return retval;
  874. X             }
  875. X            }
  876. X            continue;
  877. X           }
  878. X           else {
  879. X            retval = add_str(found, *num_found,
  880. X                     append(base, dp->d_name));
  881. X            if (retval) {
  882. X             error("add_str");
  883. X             (void) popall();
  884. X             return retval;
  885. X            }
  886. X            (*num_found)++;
  887. X           }
  888. X      }
  889. X
  890. X      if (! is_dotfile(dp->d_name)) {
  891. X           if (options & RECURS_FIND_DELETED)
  892. X            goto downdir;
  893. X           if (options & RECURS_FIND_UNDELETED)
  894. X            goto downdir;
  895. X      }
  896. X      
  897. X      continue;
  898. X      
  899. X           
  900. X     downdir:
  901. X      retval = push(&dirp, sizeof(DIR *));
  902. X      if (retval) {
  903. X           error("push");
  904. X           (void) popall();
  905. X           return retval;
  906. X      }
  907. X      string_push(base);
  908. X      (void) strcpy(base, append(base, dp->d_name));
  909. X
  910. X      /*
  911. X       * Originally, I did an Opendir() right at the start and
  912. X       * then only checked things if the Opendir resulted in an
  913. X       * error.  However, this is inefficient, because the
  914. X       * Opendir() procedure works by first calling open() on the
  915. X       * file, and *then* calling fstat on the file descriptor
  916. X       * that is returned.  since most of the time we will be
  917. X       * trying to open things that are not directory, it is much
  918. X       * more effecient to do the stat first here and to do the
  919. X       * Opendir only if the stat results are satisfactory.
  920. X       */
  921. X      use_stat = (options & FOLLW_LINKS) && (! is_deleted(lastpart(base)));
  922. X      if (use_stat)
  923. X           retval = stat(base, &statbuf);
  924. X      else
  925. X           retval = lstat(base, &statbuf);
  926. X      if (retval == -1) {
  927. X           set_error(errno);
  928. X           error(base);
  929. X           string_pop(base);
  930. X           (void) pop(&dirp, sizeof(DIR *));
  931. X           continue;
  932. X      }
  933. X      /* It's not a directory, so punt it and continue. */
  934. X      if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
  935. X           string_pop(base);
  936. X           (void) pop(&dirp, sizeof(DIR *));
  937. X           continue;
  938. X      }
  939. X
  940. X      /* Actually try to open it. */
  941. X      dirp = Opendir(base);
  942. X      if (! dirp) {
  943. X           set_error(errno);
  944. X           error(base);
  945. X           string_pop(base);
  946. X           (void) pop(&dirp, sizeof(DIR *));
  947. X           continue;
  948. X      }
  949. X      
  950. X      if (! (options & FOLLW_MOUNTPOINTS)) {
  951. X           if (is_mountpoint(base, use_stat ? (struct stat *) NULL :
  952. X                 &statbuf)) {
  953. X            closedir(dirp);
  954. X            set_warning(PAT_IS_MOUNT);
  955. X            error(base);
  956. X            string_pop(base);
  957. X            (void) pop(&dirp, sizeof(DIR *));
  958. X            continue;
  959. X           }
  960. X#ifdef DEBUG
  961. X           else {
  962. X            fprintf(stderr,
  963. X                "do_recurs: %s isn't a mountpoint, following.\n",
  964. X                base);
  965. X           }
  966. X#endif
  967. X      }
  968. X#ifdef DEBUG
  969. X      printf("do_recurs: opening %s\n", base);
  970. X#endif
  971. X      continue;
  972. X      
  973. X     updir:
  974. X      closedir(dirp);
  975. X      string_pop(base);
  976. X      if (retval) {
  977. X           if (retval != STACK_EMPTY) {
  978. X            error("pop");
  979. X            (void) popall();
  980. X            return retval;
  981. X           }
  982. X           return 0;
  983. X      }
  984. X      retval = pop(&dirp, sizeof(DIR *));
  985. X      if (retval) {
  986. X           error("pop");
  987. X           (void) popall();
  988. X           return retval;
  989. X      }
  990. X      continue;
  991. X     }
  992. X}
  993. X
  994. X
  995. Xvoid free_list(list, num)
  996. Xchar **list;
  997. Xint num;
  998. X{
  999. X     int i;
  1000. X
  1001. X     for (i = 0; i < num; i++)
  1002. X      free(list[i]);
  1003. X
  1004. X     free((char *) list);
  1005. X}
  1006. X
  1007. X
  1008. X
  1009. X
  1010. X
  1011. X
  1012. X/*
  1013. X * returns true if the filename has no globbing wildcards in it.  That
  1014. X * means no non-quoted question marks, asterisks, or open square
  1015. X * braces.  Assumes a null-terminated string, and a valid globbing
  1016. X */
  1017. Xint no_wildcards(name)
  1018. Xchar *name;
  1019. X{
  1020. X     do {
  1021. X      switch (*name) {
  1022. X      case '\\':
  1023. X           name++;
  1024. X           break;
  1025. X      case '?':
  1026. X           return(0);
  1027. X      case '*':
  1028. X           return(0);
  1029. X      case '[':
  1030. X           return(0);
  1031. X      }
  1032. X     } while (*++name);
  1033. X     return(1);
  1034. X}
  1035. END_OF_FILE
  1036. if test 25764 -ne `wc -c <'pattern.c'`; then
  1037.     echo shar: \"'pattern.c'\" unpacked with wrong size!
  1038. fi
  1039. # end of 'pattern.c'
  1040. fi
  1041. echo shar: End of archive 4 \(of 4\).
  1042. cp /dev/null ark4isdone
  1043. MISSING=""
  1044. for I in 1 2 3 4 ; do
  1045.     if test ! -f ark${I}isdone ; then
  1046.     MISSING="${MISSING} ${I}"
  1047.     fi
  1048. done
  1049. if test "${MISSING}" = "" ; then
  1050.     echo You have unpacked all 4 archives.
  1051.     rm -f ark[1-9]isdone
  1052. else
  1053.     echo You still need to unpack the following archives:
  1054.     echo "        " ${MISSING}
  1055. fi
  1056. ##  End of shell archive.
  1057. exit 0
  1058.  
  1059. exit 0 # Just in case...
  1060. -- 
  1061. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1062. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1063. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1064. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1065.